// 将原本需要通过传入回调参数来实现回调执行改为用promise的.then的方式来调用，从而实现逻辑上的同步操作
// fn <function> 被包装的函数
// callbackErr <boolean> (default:true) fn的回调函数参数，其第一个参数是否为error对象
// reverse <boolean> (default:false) fn的回调函数参数，是否是第一个参数（如setTimeout）
export const promisify = (fn, callbackErr = true, reverse = false) => {
  if ({}.toString.call(fn) !== `[object Function]`) {
    throw new TypeError('Only normal function can be promisified');
  }
  return function (...args) {
    return new Promise((resolve, reject) => {
      const callback = function (...args) {
        if (!callbackErr) {
          args.length === 1 ? resolve(args[0]) : resolve(args);
          return;
        }
        const err = args.shift();
        const rest = args;
        if ({}.toString.call(err) === `[object Error]`) {
          reject(err);
        }
        resolve(rest);
      };
      /*
      给fn函数主要塞入一个callback，这样在fn中调用callback的时候实际执行的时候就是
      我们这里定义的callback函数，然后在我们的callback中调用resolve，
      这样一来，本来想要通过回调执行的操作就可以放在then函数中执行了
      */
      // fn.apply(null, [...args, callback]);
      try {
        if (reverse) {
          fn.apply(null, [callback, ...args]);
        } else {
          fn.apply(null, [...args, callback]);
        }
      } catch (error) {
        reject(error);
      }
    });
  };
};
